package ms.core.gateway.system;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.servlet.AsyncContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import ms.core.common.ConfAnnexDir;
import ms.core.gateway.delegate.IAppDelegate;
import ms.core.gateway.delegate.ICorpDelegate;
import ms.core.gateway.delegate.IUserDelegate;
import ms.core.gateway.dto.Api;
import ms.core.gateway.servlet.ServletExecutor;
import ms.core.gateway.tool.ApiLoadTool;
import ms.core.gateway.tool.SessionTool;
import ms.core.gateway.utils.LWGUtils;
import ms.core.tool.Log4j2Tool;
import ms.core.tool.PropTool;
import ms.core.tool.StrTool;

public class Application {
	private static boolean inited 		= false;
	private static String confFile 		= "/config/system.properties";
	private static String sysApiConf 	= "/config/sysApi.xml";
	private static String webApiConf 	= "/config/webApi.xml";
	private static String pubApiConf 	= "/config/pubApi.xml";

	public static String UTF8 			= "utf-8";

	public static String APP_NAME;				// 应用名称
	public static String APP_PATH;				// 应用路径
	public static String DIR_FILE_CACHE;		// 上传文件缓存路径
	public static String DIR_FILE_SAVETO;		// 上传文件保存路径
	public static ConfAnnexDir DIR_PORTRAIT;	// 个人肖像保存位置
	public static ConfAnnexDir DIR_CORP_DOC;	// 企业资料保存位置
	public static String KEY_SALT;				// 密码附加串 key = md5(password+KEY_SALT)
	public static boolean LOGEVENT;				// 是否记录日志
	public static boolean DEBUG;				// 是否开启debug模式

	public static boolean CODE_LOGIN;			// 登录需验证码
	public static int CODE_LENGTH;				// 验证码长度
	public static int PAGE_SIZE;				// 页大小
	public static int SESSION_EXPIRY;			// 会话有效期(分钟)

	public static String APP_DELEGATE;			// 应用委托类名
	public static String USER_DELEGATE;			// 用户委托类名
	public static String CORP_DELEGATE;			// 企业委托类名

	// 异步servlet配置参数
	public static boolean ASYNC_SERVLET;		// 是否启用异步servlet
	public static int CORE_POOLS;				// 执行异步servlet核心线程数
	public static int MAX_POOLS;				// 执行异步servlet最大线程数
	public static int KEEP_ALIVE_TIME;			// 超过核心线程数时,空闲线程存活超时时间(单位毫秒)设置(超时的线程将被回收)
	public static int QUEUE_SIZE;				// 放置异步servlet上下文对象的队列长度
	
	// 全局对象
	private static ThreadPoolExecutor executor = null;		// 异步servlet执行线程池
	public static IAppDelegate appDelegate = null;			// 应用委托对象
	public static IUserDelegate userDelegate = null;		// 用户委托对象
	public static ICorpDelegate corpDelegate = null;		// 企业委托类
	private static Map<String, Api> sysApi = null;			// 框架api
	private static Map<String, Api> webApi = null;			// 应用api
	private static Map<String, Api> pubApi = null;			// authapi

	private static void loadParam() {
		PropTool tool = PropTool.getInstance(confFile);
		APP_NAME 		= tool.getValue("appName", "helios");
		APP_PATH 		= tool.getValue("appPath", "");
		DIR_FILE_CACHE	= tool.getValue("dirFileCache", "");
		DIR_FILE_SAVETO = tool.getValue("dirFileSaveTo", "");
		DIR_PORTRAIT	= ConfAnnexDir.getInstance(tool.getValue("dirPortrait", ""));
		DIR_CORP_DOC	= ConfAnnexDir.getInstance(tool.getValue("dirCorpDoc", ""));
		KEY_SALT 		= tool.getValue("keySalt", "");
		LOGEVENT 		= "true".equalsIgnoreCase(tool.getValue("logEvent", "true"));
		DEBUG 	 		= "true".equalsIgnoreCase(tool.getValue("debug", "true"));

		CODE_LOGIN		= "true".equalsIgnoreCase(tool.getValue("codeLogin", "true"));
		CODE_LENGTH 	= StrTool.strToInt(tool.getValue("codeLen", "4"), 4);
		PAGE_SIZE   	= StrTool.strToInt(tool.getValue("pageSize", "20"), 20);
		SESSION_EXPIRY  = StrTool.strToInt(tool.getValue("sessionExpiry", "120"), 120);

		APP_DELEGATE 	= tool.getValue("appDelegate", "");
		USER_DELEGATE 	= tool.getValue("userDelegate", "");
		CORP_DELEGATE	= tool.getValue("corpDelegate", "");

		ASYNC_SERVLET	= "true".equalsIgnoreCase(tool.getValue("asyncServlet", "true"));
		CORE_POOLS 		= StrTool.strToInt(tool.getValue("CORE_POOLS", "100"), 100);
		MAX_POOLS 		= StrTool.strToInt(tool.getValue("maxPools", "1000"), 1000);
		KEEP_ALIVE_TIME	= StrTool.strToInt(tool.getValue("keepAliveTime", "3000"), 3000);
		QUEUE_SIZE		= StrTool.strToInt(tool.getValue("queueSize", "500"), 500);
	}

	public static String getSystemProperty(String key, String defaultValue) {
		PropTool tool = PropTool.getInstance(confFile);
		return tool.getValue(key, defaultValue);
	}

	private static void initDelegate() {
		// 应用程序委托对象
		try {
			if (!StrTool.isBlank(APP_DELEGATE)) {
				Class<?> cls=Class.forName(APP_DELEGATE);
				appDelegate = cls.asSubclass(IAppDelegate.class).newInstance();
				appDelegate.afterAppInited();
			}
		} catch(Exception e) {
			Log4j2Tool.error(Application.class, e);
		}
		
		// 用户管理委托对象
		try {
			if (!StrTool.isBlank(USER_DELEGATE)) {
				Class<?> cls=Class.forName(USER_DELEGATE);
				userDelegate = cls.asSubclass(IUserDelegate.class).newInstance();
			}
		} catch(Exception e) {
			Log4j2Tool.error(Application.class, e);
		}

		// 企业管理委托对象
		try {
			if (!StrTool.isBlank(CORP_DELEGATE)) {
				Class<?> cls=Class.forName(CORP_DELEGATE);
				corpDelegate = cls.asSubclass(ICorpDelegate.class).newInstance();
			}
		} catch(Exception e) {
			Log4j2Tool.error(Application.class, e);
		}		
	}

	private static void initAsyncServletThreadPool(ServletContextEvent sce) {
		if (ASYNC_SERVLET) {
			executor = new ThreadPoolExecutor(Application.CORE_POOLS, 
						 					  Application.MAX_POOLS, 
						 					  Application.KEEP_ALIVE_TIME, 
						 					  TimeUnit.MILLISECONDS,
						 					  new LinkedBlockingQueue<Runnable>(Application.QUEUE_SIZE), 
						 					  new ThreadPoolExecutor.DiscardPolicy());
		}
	}

	/**
	 * 加载api列表
	 */
	private static void loadApi() {
		sysApi = ApiLoadTool.loadApi(0, sysApiConf);
		webApi = ApiLoadTool.loadApi(1, webApiConf);
		pubApi = ApiLoadTool.loadApi(2, pubApiConf);
	}

	public static void start(ServletContextEvent sce) {
		if (!inited) {
			loadParam();						// 加载 system.properties 配置参数				
			initAsyncServletThreadPool(sce);	// 初始化异步servlet线程池
			initDelegate();						// 初始化应用程序委托对象
			loadApi();							// 加载api配置表
			SessionTool.init();					// 初始化session
			LWGUtils.init(); 					// 初始化微服务配置文件
			inited = true;
		}
	}

	private static Api getApi(int type, String func) {
		switch(type) {
			case 0: return sysApi.get(func);
			case 1: return webApi.get(func);
			case 2: return pubApi.get(func);
			default: return null;
		}
	}

	/**
	 * 获取api列表
	 * 
	 * @param type 接口类型
	 * @return
	 */
	public static List<Api> getApiList(int type) {
		List<Api> list = new ArrayList<>();
		Map<String, Api> map = null;
		switch(type) {
			case 0: 
				map = sysApi;
				break;
			case 1: 
				map = webApi;
				break;
			case 2: 
				map = pubApi;
				break;
			default: return list;
		}
		
		for(Map.Entry<String, Api> entry: map.entrySet()) {
			list.add(entry.getValue());
		}
		
		return list;
	}

	/**
	 * 获取api列表
	 * 
	 * @param type 接口类型
	 * @return
	 */
	public static Map<String, Api> getApi(int type) {
		switch(type) {
			case 0: return sysApi;
			case 1: return webApi;
			case 2: return pubApi;
			default: return null;
		}
	}

	/**
	 * 异步响应servlet
	 * @param type
	 * @param func
	 * @param ctx
	 */
	public static void executeRequest(int type, String func, AsyncContext ctx) {
		if (executor==null) return;

		Api api = getApi(type, func);
		executor.execute(new ServletExecutor(api, ctx));
		if (appDelegate!=null) appDelegate.afterSessionEnded();
	}
	
	/**
	 * 同步响应servlet
	 * @param type 0-系统;1-应用;2-授权api
	 * @param func
	 * @param req
	 * @param resp
	 */
	public static void executeRequest(int type, String func, HttpServletRequest req, HttpServletResponse resp) {
		Api api = getApi(type, func);
		ServletExecutor.ackRequest(api, req, resp);
		if (appDelegate!=null) appDelegate.afterSessionEnded();
	}

	public static void stop(ServletContextEvent sce) {
		if (executor!=null) {
			 executor.shutdown();
		}

		if (appDelegate!=null) {
			appDelegate.afterAppDestroy();
		}
	}
}